package com.shen.jcbf.jdk8bf.forkjoin;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

/**
 * 说明：jdk7 的 ForkJoin 测试3，实例理解
 * 
 * @author shenhx
 * @date 2017年6月20日
 */
public class ForkJoinTest3 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 生成随机矩阵
		final int rows = 10000; // 矩阵行数
		final int cols = 10000; // 矩阵列数
		final int number = 5; // 查找的数字
		long start = System.currentTimeMillis();
		MatrixMock mock = new MatrixMock(rows, cols, number); // 生成矩阵对象
		long end = System.currentTimeMillis();
		System.out.println("创建矩阵花费时间:" + (end - start));

		// 执行任务
		ForkJoinPool pool = new ForkJoinPool();
		Task2 task = new Task2(mock, 0, rows, 5);

		start = System.currentTimeMillis();
		pool.execute(task);
		do {
			//Thread.sleep(5000);
			System.out.printf("活跃线程：%s,这一个参数  %s,并行执行的最大数量：%s\n", pool.getActiveThreadCount(), pool.getStealCount(),pool.getParallelism());
		} while (!task.isDone()); // 如果任务还未完成，则继续获取信息
		
		pool.shutdown();
		//
		pool.awaitTermination(1, TimeUnit.MILLISECONDS);
		System.out.println("线程搜索的结果是：" + task.get());

		end = System.currentTimeMillis();
		System.out.println("线程搜索时间是:" + (end - start));

		start = System.currentTimeMillis();
		int temp = 0;
		for (int i = 0; i < rows; i++) {
			int[] rs = mock.getRow(i);
			for (int row : rs) {
				if (5 == row) {
					temp++;
				}
			}
		}
		end = System.currentTimeMillis();
		System.out.println(end + "---" + start);
		System.out.println("单线程搜索结果是：" + temp);
		System.out.println("单线程搜索时间是:" + (end - start));
	}
}

// 任务类。查找数字出现的次数
class Task2 extends RecursiveTask<Integer> {
	private static final long serialVersionUID = 1L;
	private MatrixMock mock;
	private int start; // 查询起始行索引
	private int end; // 查询结束行索引
	private int num; // 要查找的数字

	public Task2(MatrixMock mock, int start, int end, int num) {
		this.mock = mock;
		this.start = start;
		this.end = end;
		this.num = num;
	}

	@Override
	protected Integer compute() {
		int result = 0;

		if (end - start < 100) { // 每个任务最多负责   X 行数据
			result = this.search();
			// 适合矩阵小的时候 查看对比结果
			// System.out.printf("%s,搜索起始行是：%s-%s,搜索结果是：%s\n",Thread.currentThread().getName(),start,end,result);
		} else { // 否则则拆分成两个子任务
			int mid = (end + start) / 2;
			Task2 task1 = new Task2(mock, start, mid, num);
			Task2 task2 = new Task2(mock, mid, end, num);
			invokeAll(task1, task2);
			try {
				result = task1.get() + task2.get(); // 两个结果相加，要想到 该框架的特性就是 递归
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	// 计算当前任务分配的行数
	private int search() {
		int result = 0;
		for (int i = start; i < end; i++) {
			int[] rows = mock.getRow(i);
			for (int row : rows) {
				if (num == row) {
					result++;
				}
			}
		}
		return result;
	}
}

// 随机矩阵
class MatrixMock {
	private int[][] data;

	public MatrixMock(int size, int cols, int number) {
		data = new int[size][cols];
		Random random = new Random();

		int counter = 0;
		// 用随机数为矩阵赋值。每生成一个字，就用它跟要查找的数字比较，进行比较。如果一致，就用计数器加1
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < cols; j++) {
				data[i][j] = random.nextInt(10);
				if (data[i][j] == number) {
					counter++;
				}
			}
		}
		// 用来验证多线程查找的正确性
		System.out.printf("创建矩阵完毕，待查询数字：%d,%d次\n", number, counter);
		
		
		// 测试的时候，可以放开此代码，能打印出 矩阵分布图。当然需要矩阵10 * 10 比较小的收，控制台才能装得下
//		for (int i = 0; i < data.length; i++) {
//			for (int j = 0; j < data[i].length; j++) {
//				System.out.printf(data[i][j] + " | ");
//			}
//			System.out.println("");
//		}
		
		// 测试的时候，可以放开此代码，生成文件 矩阵分布图
//		try {
//			FileOutputStream fo = new FileOutputStream("D:\\矩阵分布图\\aabb.xml");
//			for (int i = 0; i < data.length; i++) {
//				for (int j = 0; j < data[i].length; j++) {
//					fo.write((data[i][j] + " | ").getBytes());
//				}
//				fo.write("\r\n".getBytes());
//			}
//			fo.close();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		
		
	}

	/**
	 * 说明：获取指定一行的数据
	 */
	public int[] getRow(int row) {
		if (row >= 0 && row < data.length) {
			return data[row];
		}
		return null;
	}
}
